package com.android.volley.toolbox;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.huyn.baseframework.utils.Constant;
import com.huyn.baseframework.utils.StringUtils;

/**
 * Created by Andy.fang on 2015/12/29.
 */
public class SuperImageRequest extends Request<SuperImageObject> {

    private String mLocalPath;

    public SuperImageRequest(String url, Response.Listener<SuperImageObject> listener, Response.ProgressListener progressListener) {
        super(Method.GET, url, listener);
        setProgressListener(progressListener);
    }

    public void setLocalPath(String path) {
        this.mLocalPath = path;
    }

    public String getLocalPath() {
        return mLocalPath;
    }

    @Override
    protected Response<SuperImageObject> parseNetworkResponse(NetworkResponse response) {
        try {
            if(response.storeToLocal)
                return Response.success(new SuperImageObject(new String(response.data, HttpHeaderParser.parseCharset(response.headers)), null), HttpHeaderParser.parseCacheHeaders(response));
            else
                return doParse(response);
        } catch (Exception e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        }
    }

    @Override
    public void deliverResponse(SuperImageObject response) {
        if(mListener != null)
            mListener.onResponse(response);
    }

    public void deliverProgress(float progress) {
        if(mProgressListener != null)
            mProgressListener.onProgress(progress);
    }

    private int mMaxHeight=0, mMaxWidth=0;
    private String mPreviewImg;

    public void setPreviewImg(String url) {
        mPreviewImg = url;
        mMaxHeight = mMaxWidth = 0;
    }

    public String getPreviewCacheKey() {
        if(StringUtils.isBlank(mPreviewImg))
            return null;
        return ImageLoader.getCacheKey(mPreviewImg, mMaxWidth, mMaxHeight);
    }

    private Response<SuperImageObject> doParse(NetworkResponse response) {
        // start to parse diskcached data or network data
        if(Constant.IMG_DEBUG) {
            Log.i("VOLLEYIMG", "START TO PARSE " + getUrl());
        }
        byte[] data = response.data;

        if(data == null)
            return Response.error(new ParseError());

        Bitmap bitmap = null;

        //如果返回no right！
        if(data.length <= 10)
            return Response.error(new ParseError());

        //给测试用，记录图片size
        if(Constant.IMG_DEBUG) {
            Log.i("VOLLEYIMG", getUrl() + ";size:" + data.length);
        }

        BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
        if (mMaxWidth == 0 && mMaxHeight == 0) {
            decodeOptions.inPreferredConfig = Bitmap.Config.RGB_565;
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
        } else {
            // If we have to resize this image, first get the natural bounds.
            decodeOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
            int actualWidth = decodeOptions.outWidth;
            int actualHeight = decodeOptions.outHeight;

            // Then compute the dimensions we would ideally like to decode to.
            int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,
                    actualWidth, actualHeight);
            int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
                    actualHeight, actualWidth);

            // Decode to the nearest power of two scaling factor.
            decodeOptions.inJustDecodeBounds = false;
            decodeOptions.inPreferredConfig = Constant.BITMAP_CONFIG;
            decodeOptions.inInputShareable = true;
            decodeOptions.inPurgeable = true;
            // Do we need this or is it okay since API 8 doesn't support it?
            // decodeOptions.inPreferQualityOverSpeed = PREFER_QUALITY_OVER_SPEED;
            decodeOptions.inSampleSize =
                    ImageRequest.findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
            Bitmap tempBitmap =
                    BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);

            // If necessary, scale down to the maximal acceptable size.
            if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth ||
                    tempBitmap.getHeight() > desiredHeight)) {
                bitmap = Bitmap.createScaledBitmap(tempBitmap,
                        desiredWidth, desiredHeight, true);
                tempBitmap.recycle();
            } else {
                bitmap = tempBitmap;
            }
        }

        if (bitmap == null) {
            return Response.error(new ParseError());
        } else {
            return Response.success(new SuperImageObject(null, bitmap), HttpHeaderParser.parseCacheHeaders(response));
        }
    }

    /**
     * Scales one side of a rectangle to fit aspect ratio.
     *
     * @param maxPrimary Maximum size of the primary dimension (i.e. width for
     *        max width), or zero to maintain aspect ratio with secondary
     *        dimension
     * @param maxSecondary Maximum size of the secondary dimension, or zero to
     *        maintain aspect ratio with primary dimension
     * @param actualPrimary Actual size of the primary dimension
     * @param actualSecondary Actual size of the secondary dimension
     */
    private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary,
                                           int actualSecondary) {
        // If no dominant value at all, just return the actual.
        if (maxPrimary == 0 && maxSecondary == 0) {
            return actualPrimary;
        }

        // If primary is unspecified, scale primary to match secondary's scaling ratio.
        if (maxPrimary == 0) {
            double ratio = (double) maxSecondary / (double) actualSecondary;
            return (int) (actualPrimary * ratio);
        }

        if (maxSecondary == 0) {
            return maxPrimary;
        }

        double ratio = (double) actualSecondary / (double) actualPrimary;
        int resized = maxPrimary;
        if (resized * ratio > maxSecondary) {
            resized = (int) (maxSecondary / ratio);
        }
        return resized;
    }

}
